/*********************
* Author:Dzlua
* QQ:505544956
* time:2016/09/16
*/
#include "Slider.h"
#include "../edui.h"

EDUI_NAMESPACE_BEGIN

Slider* Slider::GetInterface()
{
    Slider* slider = new Slider;
#ifdef EDUI_TEST_NEW_DELETE
    ++m_newdeleteNum;
    Log("[Slider] new slider : %d", slider);
#endif
#ifdef EDUI_USE_LUAPLUS
    LuaMgrPtr->Add("Slider", slider);
#endif
    return slider;
}

void Slider::Release()
{
#ifdef EDUI_TEST_NEW_DELETE
    --m_newdeleteNum;
    Log("[Slider] delete slider : %s, %d", this->GetName(), this);
#endif
#ifdef EDUI_USE_LUAPLUS
    LuaMgrPtr->Remove(this);
#endif
    delete this;
}

Slider* Slider::ToSlider(Control* ctrl)
{
    return dynamic_cast<Slider*>(ctrl);
}

Slider::Slider() : m_thumbState(BUTTON_STATE_NORMAL), m_step(1), m_mouseMove(false)
{
    m_bKeyboardEnabled = true;
}

Slider::~Slider()
{}

void Slider::SetStep(int step)
{
    m_step = step;
}
 
int Slider::GetStep() const
{
    return m_step;
}

bool Slider::SetRect(const Rect *rc)
{
    if (!rc) return false;
    if (rc->x == m_rc.x && rc->y == m_rc.y && rc->w == m_rc.w && rc->h == m_rc.h) return true;

    m_rc = *rc;

    Rect rcbarbk = this->GetBarBkRect();
    if ((m_maxVal > m_minVal) && (m_val <= m_maxVal) && (m_val >= m_minVal)){
        if (m_type == 0){
            m_thumbPt.x = rcbarbk.w * (m_val - m_minVal) / (m_maxVal - m_minVal);
            m_thumbPt.y = rcbarbk.h / 2;
        } else if (m_type == 1){
            int h = rcbarbk.h * (m_val - m_minVal) / (m_maxVal - m_minVal);
            m_thumbPt.y = rcbarbk.h - h;
            m_thumbPt.x = rcbarbk.w / 2;
        } else if (m_type == 2){
            int w = rcbarbk.w * (m_val - m_minVal) / (m_maxVal - m_minVal);
            m_thumbPt.x = rcbarbk.w - w;
            m_thumbPt.y = rcbarbk.h / 2;
        } else if (m_type == 3){
            m_thumbPt.y = rcbarbk.h * (m_val - m_minVal) / (m_maxVal - m_minVal);
            m_thumbPt.x = rcbarbk.w / 2;
        }
    }
    return true;
}

void Slider::SetThumbSize(int w, int h)
{
    if (w > 0 && h > 0){
        m_thumbSize.w = w;
        m_thumbSize.h = h;
    }
}

Size Slider::GetThumbSize()
{
    return m_thumbSize;
}

Rect Slider::GetThumbRect()
{
    Rect rc = this->GetBarBkRect();

    rc.x += m_thumbPt.x - m_thumbSize.w / 2;
    rc.y += m_thumbPt.y - m_thumbSize.h / 2;
    rc.w = m_thumbSize.w;
    rc.h = m_thumbSize.h;

    return rc;
}

Rect Slider::GetBarRect()
{
    Rect rc = this->GetBarBkRect();

    if (m_type == 0) rc.w = m_thumbPt.x;
    else if(m_type == 1){
        rc.y += m_thumbPt.y;
        rc.h = rc.h - m_thumbPt.y;
    } if(m_type == 2){
        rc.x += m_thumbPt.x;
        rc.w = rc.w - m_thumbPt.x;
    } if(m_type == 3) rc.h = m_thumbPt.y;

    return rc;
}

bool Slider::SetValue(int val)
{
    if (val < m_minVal) val = m_minVal;
    if (val > m_maxVal) val = m_maxVal;
    if (val == m_val) return true;
    m_val = val;

    if ((m_maxVal > m_minVal) && (m_val <= m_maxVal) && (m_val >= m_minVal)){
        Rect rc = this->GetBarBkRect();
        if (m_type == 0) m_thumbPt.x = rc.w * (m_val - m_minVal) / (m_maxVal - m_minVal);
        else if (m_type == 1) m_thumbPt.y = rc.h - rc.h * (m_val - m_minVal) / (m_maxVal - m_minVal);
        else if (m_type == 2) m_thumbPt.x = rc.w - rc.w * (m_val - m_minVal) / (m_maxVal - m_minVal);
        else if (m_type == 3) m_thumbPt.y = rc.h * (m_val - m_minVal) / (m_maxVal - m_minVal);
    }

    this->Invaldate();
    this->DoEvent(EVENT_SCROLL);

    return true;
}

void Slider::ThumbMove(int x, int y)
{
    Rect barbkrc = this->GetBarBkRect();

    if (m_type % 2 == 0) { if (x < barbkrc.x || x > barbkrc.x + barbkrc.w) return; }
    else { if (y < barbkrc.y || y > barbkrc.y + barbkrc.h) return; }

    int val = m_val;
    if (m_type == 0){
        m_thumbPt.x = x - barbkrc.x;
        val = (m_maxVal - m_minVal) * (m_thumbPt.x) / barbkrc.w;
    } else if (m_type == 1){
        m_thumbPt.y = y - barbkrc.y;        
        val = (m_maxVal - m_minVal) * (barbkrc.h - m_thumbPt.y) / barbkrc.h;
    } else if (m_type == 2){
        m_thumbPt.x = x - barbkrc.x;
        val = (m_maxVal - m_minVal) * (barbkrc.w - m_thumbPt.x) / barbkrc.w;
    } else if (m_type == 3){
        m_thumbPt.y = y - barbkrc.y;
        val = (m_maxVal - m_minVal) * (m_thumbPt.y) / barbkrc.h;
    }

    if (val == m_val) return;

    m_val = val;

    this->DoEvent(EVENT_SCROLL);
}

bool Slider::HandleMsg(Msg* msg)
{
    bool bReDraw = false;
    bool bHandled = Progress::HandleMsg(msg);

    if (msg->msg == MSG_WND_LEAVE){
        if (m_thumbState != BUTTON_STATE_NORMAL){
            m_thumbState = BUTTON_STATE_NORMAL;
            bReDraw = true;
        }
    }

    Rect thumbrc = this->GetThumbRect();
    if (thumbrc.IsOK()){
        if (msg->msg == MSG_MOUSE_MOVE){
            MouseMoveMsg *evt = &msg->motion;
            if (thumbrc.IsInRect(evt->x, evt->y)){
                if (evt->state & MOUSE_BUTTON(MOUSE_BUTTON_LEFT)){
                    m_thumbState =  BUTTON_STATE_PRESSED;
                    m_mouseMove = true;
                    bReDraw = true;
                } else {
                    if (m_thumbState !=  BUTTON_STATE_HOT){
                        m_thumbState =  BUTTON_STATE_HOT;
                        bReDraw = true;
                    }
                }
                bHandled = true;
            } else {
                if (m_thumbState !=  BUTTON_STATE_NORMAL){
                    m_thumbState =  BUTTON_STATE_NORMAL;
                    bReDraw = true;
                }
            }

            if (m_mouseMove && m_rc.IsInRect(evt->x, evt->y)){
                this->ThumbMove(evt->x, evt->y);
                bReDraw = true;
            }
            
        } else if (msg->msg == MSG_MOUSE_BUTTON_DOWN){
            MouseButtonMsg *evt = &msg->button;
            if (thumbrc.IsInRect(evt->x, evt->y)){
                if (m_thumbState !=  BUTTON_STATE_PRESSED){
                    m_thumbState =  BUTTON_STATE_PRESSED;
                    bReDraw = true;
                }
                bHandled = true;
            }

            Rect barbkrc = this->GetBarBkRect();
            if (barbkrc.IsInRect(evt->x, evt->y)){
                this->ThumbMove(evt->x, evt->y);
                bReDraw = true;
            }
        } else if (msg->msg == MSG_MOUSE_BUTTON_UP){
            m_mouseMove = false;
            MouseButtonMsg *evt = &msg->button;
            if (thumbrc.IsInRect(evt->x, evt->y)){
                if (m_thumbState !=  BUTTON_STATE_HOT){
                    m_thumbState =  BUTTON_STATE_HOT;
                    bReDraw = true;
                }
                bHandled = true;
            } else {
                if (m_thumbState !=  BUTTON_STATE_NORMAL){
                    m_thumbState =  BUTTON_STATE_NORMAL;
                    bReDraw = true;
                }
            }
        }
    }
    
    if (msg->msg == MSG_KEY_DOWN){
        KeyboardMsg* evt = &msg->key;
        if (m_type % 2 == 0){
            if (evt->key == KEY_LEFT){
                if (m_type == 0) this->SetValue(m_val - m_step);
                else if (m_type == 2) this->SetValue(m_val + m_step);
            } else if (evt->key == KEY_RIGHT){
                if (m_type == 0) this->SetValue(m_val + m_step);
                else if (m_type == 2) this->SetValue(m_val - m_step);
            }
        } else {
            if (evt->key == KEY_UP){
                if (m_type == 1) this->SetValue(m_val + m_step);
                else if (m_type == 3) this->SetValue(m_val - m_step);
            } else if (evt->key == KEY_DOWN){
                if (m_type == 1) this->SetValue(m_val - m_step);
                else if (m_type == 3) this->SetValue(m_val + m_step);
            }
        }
    } else if (msg->msg == MSG_MOUSE_WHEEL){
        MouseWheelMsg* evt = &msg->wheel;
        if (m_type == 0) this->SetValue(m_val - m_step * evt->y);
        else if (m_type == 1) this->SetValue(m_val + m_step * evt->y);
        else if (m_type == 2) this->SetValue(m_val + m_step * evt->y);
        else if (m_type == 3) this->SetValue(m_val - m_step * evt->y);
    }

    if (bReDraw) this->Invaldate();
    return bHandled;
}

void Slider::RenderStatusImages(IRender* render, const Rect* rc)
{
    Progress::RenderStatusImages(render, rc);

    if (!m_bEnabled){
        m_thumbState = BUTTON_STATE_DISABLED;
    }

    Rect thumbRc = this->GetThumbRect();
    if (thumbRc.IsOK() && (!rc || thumbRc.IsUnion(rc))){
        if (m_thumbState == BUTTON_STATE_NORMAL){
            this->DrawImage(render, &m_thumbNoramlImage, &thumbRc);
        } else if (m_thumbState == BUTTON_STATE_HOT){
            this->DrawImage(render, &m_thumbHotImage, &thumbRc);
        } else if (m_thumbState == BUTTON_STATE_PRESSED){
            this->DrawImage(render, &m_thumbPressedImage, &thumbRc);
        } else if (m_thumbState == BUTTON_STATE_DISABLED){
            this->DrawImage(render, &m_thumbDisabledImage, &thumbRc);
        }
    }
}

ImageData* Slider::GetDestImageData(const char* value)
{
    if (0 == strcmp(value, "thumbnormal")){
        return &m_thumbNoramlImage;
    } else if (0 == strcmp(value, "tbumbhot")){
        return &m_thumbHotImage;
    } else if (0 == strcmp(value, "thumbpressed")){
        return &m_thumbPressedImage;
    } else if (0 == strcmp(value, "thumbdisabled")){
        return &m_thumbDisabledImage;
    }
    return Progress::GetDestImageData(value);
}

void Slider::SetAttribute(const char* name, const char* value)
{
    if (0 == strcmp(name, "thumbsize")){
        Size sz = ParserSize(value);
        this->SetThumbSize(sz.w, sz.h);
    } else if (0 == strcmp(name, "step")){
        ParserInt(value, &m_step, 1);
    } else {
        Progress::SetAttribute(name, value);
    }
}

void Slider::DoEvent(EventType type, void* data1, void* data2)
{
    switch (type){
        case EVENT_SCROLL : this->evt.progress.emit(this); break;
    }
#ifdef EDUI_USE_LUAPLUS
    switch (type){
        case EVENT_SCROLL : LuaMgrPtr->DoEvent(this, "progress"); break;
    }
#endif
}

EDUI_NAMESPACE_END
